package com.example.netty.Demo0;

import io.netty.buffer.*;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.*;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpObjectDecoder;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.CharsetUtil;

import java.nio.ByteBuffer;
import java.nio.IntBuffer;

public class BufferTest {
    public static void main(String[] args) {
//        IntBuffer intBuffer = IntBuffer.allocate(10);
//        intBuffer.put(10);
//        intBuffer.put(9);
//        System.err.println("Write mode: ");
//        System.err.println("\tCapacity: " + intBuffer.capacity());
//        System.err.println("\tPosition: " + intBuffer.position());
//        System.err.println("\tLimit: " + intBuffer.limit());
//
//        intBuffer.flip();
//        System.err.println("Read mode: ");
//        System.err.println("\tCapacity: " + intBuffer.capacity());
//        System.err.println("\tPosition: " + intBuffer.position());
//        System.err.println("\tLimit: " + intBuffer.limit());

        System.out.println("0-----------------------------------------------0");


//        String str = "helloWorld";
//        ByteBuffer buff  = ByteBuffer.wrap(str.getBytes());
//        System.out.println("position:"+buff.position()+"\t limit:"+buff.limit());
//        //读取两个字节
//        byte[] abytes = new byte[1];
//        buff.get(abytes);
//        System.out.println("get one byte to string:" + new String(abytes));
//        //Reads the byte at this buffer's current position, and then increments the position.
//        buff.get();
//        System.out.println("获取两个字节（两次get()方法调用）后");
//        System.out.println("position:"+buff.position()+"\t limit:"+buff.limit());
//        //Sets this buffer's mark at its position. like ByteBuffer.this.mark=position
//        buff.mark();
//        System.out.println("mark()...");
//        System.out.println("position:"+buff.position()+"\t limit:"+buff.limit());
//
//       /* 当读取到码流后，进行解码。首先对ByteBuffer进行flip操作，
//        它的作用是将缓冲区当前的limit设置为position,position设置为0
//        flip方法将Buffer从写模式切换到读模式。调用flip()方法会将position设回0，并将limit设置成之前position的值。
//　　　　　 这里的flip()方法，在详细的描述一下，其事这里是理解position和limit这两个属性的关键。
//　　　　　用于后续对缓冲区的读取操作。然后根据缓冲区可读的字节个数创建字节数组，
//        调用ByteBuffer的get操作将缓冲区可读的字节(获取position到limit的字节)
//        数组复制到新创建的字节数组中，最后调用字符串的构造函数创建请求消息体并打印。*/
//        buff.flip();
//        System.out.println("flip()...");
//        System.out.println("position:"+buff.position()+"\t limit:"+buff.limit());
//
//        byte[] tbyte = new byte[1];
//        buff.get(tbyte);
//        System.out.println("get one byte to string:" + new String(tbyte));
//        System.out.println("position:"+buff.position()+"\t limit:"+buff.limit());
//
//        //BufferUnderflowException 测试
////        byte[] trbyte = new byte[2];
////        buff.get(trbyte);
        System.out.println("0-----------------------------------------------0");


        ////重置 position
//        IntBuffer intBuffer = IntBuffer.allocate(2);
//        intBuffer.put(1);
//        intBuffer.put(2);
//        System.err.println("position: " + intBuffer.position());
//
//        intBuffer.rewind();
//        System.err.println("position: " + intBuffer.position());
//        intBuffer.put(1);
//        intBuffer.put(2);
//        System.err.println("position: " + intBuffer.position());
//
//
//        intBuffer.flip();
//        System.err.println("position: " + intBuffer.position());
//        intBuffer.get();
//        intBuffer.get();
//        System.err.println("position: " + intBuffer.position());
//
//        intBuffer.rewind();
//        System.err.println("position: " + intBuffer.position());
        System.out.println("0-----------------------------------------------0");


//        //通过调用 Buffer.mark()将当前的 position 的值保存起来, 随后可以通过调用 Buffer.reset()方法将 position 的值回复回来.
//        IntBuffer intBuffer = IntBuffer.allocate(2);
//        intBuffer.put(10);
//        intBuffer.put(20);
//        intBuffer.flip();
//        System.err.println(intBuffer.get());
//        System.err.println("position: " + intBuffer.position());
//        intBuffer.mark();
//        System.err.println(intBuffer.get());
//
//        System.err.println("position: " + intBuffer.position());
//        intBuffer.reset();
//        System.err.println("position: " + intBuffer.position());
//        System.err.println(intBuffer.get());

        System.out.println("0-----------------------------------------------0");

//        //flip, rewind 和 clear 的区别
//        IntBuffer intBuffer = IntBuffer.allocate(2);
//        intBuffer.flip();
//        System.err.println("position: " + intBuffer.position());
//        System.err.println("limit: " + intBuffer.limit());
//        System.err.println("capacity: " + intBuffer.capacity());
//
//        // 这里不能读, 因为 limit == position == 0, 没有数据.
//        //System.err.println(intBuffer.get());
//
//        intBuffer.clear();
//        System.err.println("position: " + intBuffer.position());
//        System.err.println("limit: " + intBuffer.limit());
//        System.err.println("capacity: " + intBuffer.capacity());
//
//        // 这里可以读取数据了, 因为 clear 后, limit == capacity == 2, position == 0,
//        // 即使我们没有写入任何的数据到 buffer 中.
//        System.err.println(intBuffer.get()); // 读取到0
//        System.err.println(intBuffer.get()); // 读取到0

//        ByteBuffer buff11 = ByteBuffer.allocate(222);
//        PooledByteBufAllocator pooledByteBufAllocator;
//        UnpooledByteBufAllocator unpooledByteBufAllocator;
//        ByteBufAllocator byteBufAllocator;


//        ByteBuf buf = Unpooled.buffer();
//        String str = "four you";
//        buf.writeBytes(str.getBytes());
//        System.out.println((char)buf.readByte());
//        int n = (char)buf.readerIndex();
//        System.out.println("idx-"+n );


        /*ByteBuf的可读字节分段存储了实际的数据,新分配的、包装的或者复制的缓冲区默认的读写索引都为0，
        任何一read、skip开头的操作都会使readerIndex变化，当然write相关的方法一回事writerIndex会被增加。*/
//        ByteBuf buf = Unpooled.buffer();
//        String str = "four you";
//        buf.writeBytes(str.getBytes());
//        System.out.println(buf.writerIndex());
//        buf.skipBytes(3);
//        buf.writeByte('a');
//        int n = buf.readerIndex();
//        int m = buf.writerIndex();
//        System.out.println("readerIndex:"+n+"\nwriterIndex:"+m);
//        System.out.println("readerIndex:"+n+"\nwriterIndex:"+m);


//        //查找的例子：
//        ByteBuf buf = Unpooled.buffer();
//        String str = "four you";
//        buf.writeBytes(str.getBytes());
//        int n = buf.indexOf(0,buf.capacity()-1,(byte)'r');
//        System.out.println("readerIndex:"+n);


        /*派生缓冲区
        在ByteBuf中有一些方法slice、order等方法会返回一个新的ByteBuf实例，
        它具有自己的读写索引和标记索引，但是内部存储的数组是共享的。*/
//        ByteBuf buffer = Unpooled.copiedBuffer("four you", CharsetUtil.UTF_8);
//        ByteBuf bufCopy = buffer.slice(0,3);
//        System.out.println(bufCopy.toString(CharsetUtil.UTF_8));
//            //更新索引0处的字节
//        buffer.setByte(0,(byte)'j');
//        System.out.println(bufCopy.toString(CharsetUtil.UTF_8));
//        System.out.println(buffer.toString(CharsetUtil.UTF_8));


        /*ByteBuff复制
        如果真的需要一个真实的复制品，可以使用copy方法。*/
//        ByteBuf buffer = Unpooled.copiedBuffer("four you", CharsetUtil.UTF_8);
//        ByteBuf bufCopy = buffer.copy(0,3);
//        System.out.println(bufCopy.toString(CharsetUtil.UTF_8));
//        buffer.setByte(0,(byte)'j');
//        System.out.println(bufCopy.toString(CharsetUtil.UTF_8));


//        //获取到与ChannelHandlerContext相关联的 Channel 的引用
//        ChannelHandlerContext ctx = null;
//        Channel channel = ctx.channel();
//        //通过Channel 写入缓冲区
//        //write()方法将会导致写入事件从尾端到头部地流经ChannelPipeline
//        channel.write(Unpooled.copiedBuffer("hellow", CharsetUtil.UTF_8));
//
//        ChannelHandlerContext ctx2 = null;
//        //获取到与ChannelHandlerContext相关联的ChannelPipeline 的引用
//        ChannelPipeline pipeline = ctx2.pipeline();
//        //通过 ChannelPipeline写入缓冲区
//        pipeline.write(Unpooled.copiedBuffer("hellow", CharsetUtil.UTF_8));


        /*
        CompositeByteBuf
        传统的ByteBuffer，如果需要将两个ByteBuffer中的数据组合到一起，
        我们需要首先创建一个size=size1+size2大小的新的数组，然后将两个数组中的数据拷贝到新的数组中。
        但是使用Netty提供的组合ByteBuf，就可以避免这样的操作，
        因为CompositeByteBuf并没有真正将多个Buffer组合起来，而是保存了它们的引用，从而避免了数据的拷贝，
        addComponents(boolean increaseWriterIndex, ByteBuf… buffers) 来添加两个 ByteBuf,
        其中第一个参数是 true, 表示当添加新的 ByteBuf 时, 自动递增 CompositeByteBuf 的 writeIndex*/
//        ByteBuf buf1 = Unpooled.buffer(5);
//        ByteBuf buf2 = Unpooled.buffer(10);
//        CompositeByteBuf buf = Unpooled.compositeBuffer();
//        buf.addComponents(true,buf1, buf2);


       /* Unpooled.wrappedBuffer 方法将 bytes、ByteBuffer等 包装成为一个 UnpooledHeapByteBuf 对象,
        而在包装的过程中, 是不会有拷贝操作的。
        以byte[]数组为例。生成的 ByteBuf 对象是和 byte[]数组共用了同一个存储空间,
        对 bytes 的修改也会反映到 ByteBuf 对象中.*/

//        byte[] bytes = "SSSS".getBytes();
//        ByteBuf byteBuf = Unpooled.wrappedBuffer(bytes);
//        ByteBuffer byteBuffer = ByteBuffer.wrap("vvvv".getBytes());
//        ByteBuf byteBuf2 = Unpooled.wrappedBuffer(byteBuffer);
//        ByteBuf byteBuf3 = Unpooled.wrappedBuffer(byteBuf);

        /*操作和slice 操作和 wrap 操作刚好相反, Unpooled.wrappedBuffer 可以将多个 ByteBuf 合并为一个,
        而 slice 操作可以将一个 ByteBuf 切片 为多个共享一个存储区域的 ByteBuf 对象.
        用 slice 方法产生 header 和 body 的过程是没有拷贝操作的,
        header 和 body 对象在内部其实是共享了 byteBuf 存储空间的不同部分而已. 即:*/
//        ByteBuf byteBuf = Unpooled.wrappedBuffer("oooo".getBytes());
//        ByteBuf header = byteBuf.slice(0, 5);
//        ByteBuf body = byteBuf.slice(5, 10);


        ByteToMessageDecoder ByteToMessageDecoder;
        LineBasedFrameDecoder LineBasedFrameDecoder;
        HttpObjectDecoder HttpObjectDecoder;

        MessageToByteEncoder MessageToByteEncoder;
        MessageToMessageEncoder MessageToMessageEncoder;
        DelimiterBasedFrameDecoder delimiterBasedFrameDecoder;
        FixedLengthFrameDecoder fixedLengthFrameDecoder;

        IdleStateHandler idleStateHandler;
        IdleState IdleState;
        SslHandler sslHandler;

        FullHttpRequest fullHttpRequest;
        FullHttpResponse fullHttpResponse;
    }
}
